﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Collections.Specialized;
using SCRUM.Core.BusinessObjects;

/// <summary>
/// Widget for overview of some entity.
/// Consists of filter and datagrid.
/// Properties:
///  * selected item - item on which user clicked in datagrid
///  * items - items displayed by filter
/// On datagrid can be set:
///  * page size - number of items displayed in GridView
///  * displayed columns - columns which will be displayed to user
///  Supports:
///   * paging
///   * sorting
/// </summary>
public abstract class DataOverviewWidget<itemType> : EditableWidget
    //where itemType : BusinessObject
{
    #region [ ITEMS ]
    /// <summary>
    /// Gets or sets the selected item.
    /// </summary>
    /// <value>The selected item.</value>
    protected virtual itemType selectedItem
    {
        get
        {
            if (data.SelectedIndex != -1)
            {
                int offset = this.data.PageIndex * this.data.PageSize;
                int itemIndex = offset + data.SelectedIndex;
                return items[itemIndex];
            }
            return default(itemType);
        }
        set
        {
            data.SelectedIndex = -1;
        }
    }

    /// <summary>
    /// Gets the items acording to filter.
    /// </summary>
    /// <value>The items acording to filter.</value>
    protected abstract IList<itemType> itemsAcordingToFilter { get; }

    /// <summary>
    /// Gets or sets the displayed items.
    /// </summary>
    /// <value>The items.</value>
    protected IList<itemType> items 
    {
        get
        {
            if (_items == null)
            {
                _items = itemsAcordingToFilter;
            }
            return _items;
        }
        set
        {
            _items = value;
        }
    }

    protected IList<itemType> _items;

    #endregion

    #region [ SETTINGS ]

    /// <summary>
    /// Defalut items displayed in GridView
    /// </summary>
    private const int pageSize = 5;

    /// <summary>
    /// Number of columns (from left) which are always displayed
    /// </summary>
    protected abstract int alwaysVisibleColumn { get; }

    /// <summary>
    /// List of checkboxes in available column panel (names are equal as items in columns)
    /// </summary>
    private IList<CheckBox> availableColumns = new List<CheckBox>();

    /// <summary>
    /// Gets the default settings for this widget. Page size and displayed columns are added to settings in this class.
    /// </summary>
    /// <returns></returns>
    public override StringDictionary GetDefaultSettings()
    {
        StringDictionary defaultSettings = base.GetDefaultSettings();

        // defaultna pagesize
        defaultSettings.Add("pagesize", pageSize.ToString());

        for (int i = 0; i < availableColumns.Count; i++)
        {
            if(i != alwaysVisibleColumn)
            {
                defaultSettings.Add(availableColumns[i].ID, "true");
            }
        }

        return defaultSettings;
    }

    /// <summary>
    /// Saves the settings acording to inputs
    /// </summary>
    protected void SaveSettings()
    {
        settings["pagesize"] = textBoxPageSize.Text;

        for (int i = 0; i < this.availableColumns.Count; i++)
        {
            CheckBox c = availableColumns[i];
            if (i != alwaysVisibleColumn)
            {
                settings[c.ID] = c.Checked ? "true" : "false";
            }
        }
        base.SaveSettings(settings);
    }

    /// <summary>
    /// Apllies settings on widget
    /// </summary>
    protected void ApplySettings()
    {
        this.settings = GetSettings();

        for (int i = 0; i < availableColumns.Count; i++)
        {
            if (i != alwaysVisibleColumn)
            {
                data.Columns[i].Visible = settings[availableColumns[i].ID] == "true";
            }
        }

        // nastavime konkretne nastavenia (podla kontextu settingov daneho widgetu)
        SetPageSize(Int32.Parse(this.settings["pagesize"]));
    }

    /// <summary>
    /// Display the settings acording to settings.
    /// </summary>
    protected void DisplaySettings()
    {
        this.settings = GetSettings();

        for (int i = 0; i < availableColumns.Count; i++)
        {
            if (i != alwaysVisibleColumn)
            {
                availableColumns[i].Checked = this.settings[availableColumns[i].ID] == "true";
            }
        }
        textBoxPageSize.Text = this.settings["pagesize"];
    }

    /// <summary>
    /// Loads the available columns acording to settings
    /// </summary>
    protected void LoadAvailableColumns()
    {
        availableColumns.Clear();
        for (int i = 0; i < data.Columns.Count -1; i++)
        {
            CheckBox checkBox = new CheckBox();
            checkBox.ID = data.Columns[i].SortExpression + "_visible";
            checkBox.Text = data.Columns[i].HeaderText + " ";
            //checkBox.Checked = true;
            checkBox.Visible = i != alwaysVisibleColumn;
            availableColumnsPanel.Controls.Add(checkBox);
            availableColumns.Add(checkBox);
        }
    }

    /// <summary>
    /// Sets page size for entire widget. (refresh)
    /// </summary>
    /// <param name="pageSize">count of items shown per page</param>
    protected void SetPageSize(int newPageSize)
    {
        textBoxPageSize.Text = newPageSize.ToString();
        data.PageSize = newPageSize;
    }

    /// <summary>
    /// Shows the edit area of widget
    /// </summary>
    public override void ShowEdit()
    {
        base.ShowEdit();
        DisplaySettings();
    }

    /// <summary>
    /// Shows the edit area of widget
    /// </summary>
    public override void HideEdit()
    {
        base.HideEdit();
    }
    #endregion

    #region [ DATA VIEW MANUPILATION ]
    /// <summary>
    /// User click on some sprint in Gridview
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected virtual void GridViewData_SelectedIndexChanged(object sender, EventArgs e)
    {
        RefreshWidget();
    }

    /// <summary>
    /// Handles the SelectedPageChanged event of the GridViewData control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewPageEventArgs"/> instance containing the event data.</param>
    public void GridViewData_SelectedPageChanged(object sender, GridViewPageEventArgs e)
    {
        data.SelectedIndex = -1;
        data.PageIndex = e.NewPageIndex;
        RefreshWidget();
    }

    /// <summary>
    /// User wants to sort data by some column/property
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewSortEventArgs"/> instance containing the event data.</param>
    public void SortData(Object sender, GridViewSortEventArgs e)
    {
        SortDataGrid(e);
    }

    /// <summary>
    /// Gets or sets the grid view sort direction.
    /// </summary>
    /// <value>The grid view sort direction.</value>
    public SortDirection GridViewSortDirection
    {
        get
        {
            if (ViewState["sortDirection"] == null)
                ViewState["sortDirection"] = SortDirection.Ascending;
            return (SortDirection)ViewState["sortDirection"];
        }
        set
        {
            ViewState["sortDirection"] = value;
        }
    }

    /// <summary>
    /// Sorts the data in items acording to e and binds them into widget's datagrid
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewSortEventArgs"/> instance containing the event data.</param>
    protected void SortDataGrid(GridViewSortEventArgs e)
    {
        SortDirection direction = this.GridViewSortDirection;
        this.items = items.OrderBy<itemType>(e.SortExpression, direction);
        this.data.DataSource = this.items;
        this.data.DataBind();
        this.GridViewSortDirection = direction == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending;
    }

    #endregion

    #region [ PAGE LIFECYCLE ]

    /// <summary>
    /// Refreshes whole state of the widget.
    /// </summary>
    public virtual void RefreshWidget()
    {
        this.data.DataSource = itemsAcordingToFilter;
        this.data.DataBind();
    }

    /// <summary>
    /// /// Sets handlers for events.
    /// </summary>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected override void OnInit(EventArgs e)
    {
        this.data.PageIndexChanging += new GridViewPageEventHandler(GridViewData_SelectedPageChanged);
    }

    /// <summary>
    /// Handles the PreRender event of the Page control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void Page_PreRender(object sender, EventArgs e)
    {
        ShowNoDataMessage();
    }

    protected void ShowNoDataMessage()
    {
        //if ((this.data.DataSource != null) && (this.data.DataSource as IList<object>).Count == 0)
        if(items.Count == 0)
        {
            this.ShowOperationResult(MessageType.Warning, "no_data_for_filters");
        }
    }
    #endregion

    /// <summary>
    /// Specifies read only/write mode
    /// </summary>
    public override bool ReadOnly
    {
        set
        {
            base.ReadOnly = value;
        }
    }

    #region [inherited controls mapping]

    /// <summary>
    /// Gets the gridview of where items are displayed
    /// </summary>
    /// <value>The data.</value>
    protected abstract GridView data { get; }

    /// <summary>
    /// Gets the panel with checkboxes for available columns
    /// </summary>
    /// <value>The available columns panel.</value>
    protected abstract Panel availableColumnsPanel { get; }

    /// <summary>
    /// Gets the textbox in which pagesize is set
    /// </summary>
    /// <value>The size of the text box page.</value>
    protected abstract TextBox textBoxPageSize { get; }
    #endregion
}
